package com.tarena.lbs.business.filters;

import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.common.encoder.JwtEncoder;
import com.tarena.lbs.common.principle.UserPrinciple;
import com.tarena.lbs.common.utils.AuthenticationContextUtils;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;

/**
 * 认证过滤器，用于拦截HTTP请求并解析JWT令牌，将用户认证信息存储到上下文环境中
 */
@Component
@Slf4j
public class AuthenticationFilter implements Filter {
	
	private static final String HEADER_AUTH = "Authorization";
	
	@Autowired
	private JwtEncoder<UserPrinciple> jwtEncoder;
	
	/**
	 * 滤器核心逻辑，负责解析请求中的JWT令牌，并将解析出的用户信息存入上下文环境
	 *
	 * @param servletRequest  请求对象，用于获取HTTP请求头信息
	 * @param servletResponse 响应对象，用于向客户端返回响应数据
	 * @param filterChain     过滤器链对象，用于将请求传递给下一个过滤器或目标资源
	 * @throws IOException      当发生输入输出异常时抛出
	 * @throws ServletException 当发生Servlet相关异常时抛出
	 */
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		// 准备存放当前线程的认证对象
		UserPrinciple userPrinciple = null;
		// 判断是否为HTTP请求，只有HTTP请求才包含JWT认证头
		if (servletRequest instanceof HttpServletRequest) {
			HttpServletRequest request = (HttpServletRequest) servletRequest;
			// 获取Authorization请求头中的JWT令牌
			String jwt = request.getHeader(HEADER_AUTH);
			log.debug(">>>jwt：{}", jwt);
			// 如果JWT令牌不为空，则尝试解析
			if (StringUtils.hasLength(jwt)) {
				// 解析JWT令牌获取用户认证信息
				try {
					userPrinciple = jwtEncoder.getLoginFromToken(jwt, UserPrinciple.class);
					// request.setAttribute("jwt",userPrinciple);
				} catch (BusinessException e) {
					// 解析失败时仅记录错误日志，不中断请求处理流程
					log.error("过滤器解析jwt失败", e);
				}
			}
		}
		// 将解析出的用户认证信息保存到当前线程上下文
		AuthenticationContextUtils.save(userPrinciple);
		// 继续执行过滤器链中的下一个过滤器或目标资源
		filterChain.doFilter(servletRequest, servletResponse);
		// 请求处理完成后清理当前线程上下文中的认证信息
		AuthenticationContextUtils.clear();
	}
	
}
